/*
 * Copyright (c) 2013-2018 上海汇数数据. All rights reserved.
 * @(#) FileType.java 2018-08-06 14:42
 */

package cn.jh.common.core.io;

import cn.jh.common.core.domain.EnumValue;
import cn.jh.common.core.domain.TextValueContainer;
import cn.jh.common.core.i18n.I18n;
import com.fasterxml.jackson.annotation.JsonValue;
import com.google.common.collect.ImmutableList;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;

import java.beans.PropertyEditor;
import java.beans.PropertyEditorSupport;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


/**
 * 常用的文件类型枚举。
 *
 * @author Fuchun
 * @since 1.0
 */
@SuppressWarnings("ImmutableEnumChecker")
public enum FileType implements EnumValue<String>, TextValueContainer<FileType, String, String> {

    /**
     * 未知文件，以二进制文件表示。
     */
    UNKNOWN("unknown", "file.type.unknown", "未知", "application/octet-stream"),

    /**
     * 虚拟目录（特殊的{@code FileType}）。
     */
    DIRECTORY("dir", "file.type.directory", "虚拟目录", ""),

    /**
     * 图片文件：JPEG, PNG, GIF, ICO...
     */
    IMAGE("image", "file.type.image", "图片文件", "image/*"),

    /**
     * 音频文件：MP3, WAV, WMA, APE, FLAC...
     */
    AUDIO("radio", "file.type.radio", "音频文件", "audio/*"),

    /**
     * 视频文件：MP4, AVI, MPG, MOV, SWF, FLA...
     */
    VIDEO("video", "file.type.video", "视频文件", "video/*"),

    /**
     * 压缩文件：ZIP, RAR, 7Z, GZ, Z...
     */
    COMPRESSED("compressed", "file.type.compressed", "压缩文件", "application/x-*"),

    /**
     * 文档文件：TXT, DOC, XLS, PDF, XML, HTML...
     */
    DOCUMENT("document", "file.type.document", "文档文件", "text/*,application/*"),

    // 图片 JPG, PNG, GIF
    JPEG("jpg", "file.type.jpg", "JPG", "image/jpeg", IMAGE),

    PNG("png", "file.type.png", "PNG", "image/png", IMAGE),

    GIF("gif", "file.type.gif", "GIF", "image/gif", IMAGE),

    BMP("bmp", "file.type.bmp", "BMP", "application/x-bmp", IMAGE),

    WBMP("wbmp", "file.type.wbmp", "WBMP", "image/vnd.wap.wbmp", IMAGE),

    ICO("ico", "file.type.ico", "ICO", "image/x-icon", IMAGE),

    // 音频文件

    MP3("mp3", "file.type.mp3", "MP3", "audio/mp3", AUDIO),

    WAV("wav", "file.type.wav", "WAV", "audio/wav", AUDIO),

    WMA("wma", "file.type.wma", "WMA", "audio/x-ms-wma", AUDIO),

    APE("ape", "file.type.ape", "APE", "audio/x-ape", AUDIO),

    FLAC("flac", "file.type.flac", "FLAC", "audio/x-flac", AUDIO),

    // 视频文件

    MP4("mp4", "file.type.mp4", "MP4", "video/mpeg4", VIDEO),

    AVI("avi", "file.type.avi", "AVI", "video/avi", VIDEO),

    MPG("mpg", "file.type.mpg", "MPG", "video/mpg", VIDEO),

    MOV("mov", "file.type.mov", "MOV", "video/quicktime", VIDEO),

    SWF("swf", "file.type.swf", "SWF", "application/x-shockwave-flash", VIDEO),

    FLA("fla", "file.type.fla", "Flash AV", "application/octet-stream", VIDEO),

    // 压缩文件

    ZIP("zip", "file.type.zip", "ZIP", "application/zip", COMPRESSED),

    RAR("rar", "file.type.rar", "RAR", "application/x-rar-compressed", COMPRESSED),

    Z7("7z", "file.type.7z", "7Z", "application/x-7z-compressed", COMPRESSED),

    GZ("gz", "file.type.gz", "GZ", "application/x-gzip", COMPRESSED),

    Z("z", "file.type.z", "Z", "appication/x-compress", COMPRESSED),

    // 文档

    TXT("txt", "file.type.txt", "TEXT", "text/plain", DOCUMENT),

    JSON("json", "file.type.json", "JSON", "application/json", DOCUMENT),

    JS("js", "file.type.js", "JS", "application/x-javascript", DOCUMENT),

    CSS("css", "file.type.css", "CSS", "text/css", DOCUMENT),

    INI("ini", "file.type.ini", "INI", "text/plain", DOCUMENT),

    HTML("html", "file.type.html", "HTML", "text/html", DOCUMENT),

    XML("xml", "file.type.xml", "XML", "text/xml", DOCUMENT),

    PDF("pdf", "file.type.pdf", "PDF", "application/pdf", DOCUMENT),

    RTF("rtf", "file.type.rtf", "RTF", "application/rtf", DOCUMENT),

    DOC("doc", "file.type.doc", "Word-97/2000/2003", "application/msword", DOCUMENT),

    DOCX("docx", "file.type.docx", "word2007+", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", DOCUMENT),

    XLS("xls", "file.type.xsl", "Excel-97/2000/2003", "application/vnd.ms-excel", DOCUMENT),

    XLSX("xlsx", "file.type.xlsx", "Excel2007+", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", DOCUMENT),

    PPT("ppt", "file.type.ppt", "PPT-97/2000/2003", "application/vnd.ms-powerpoint", DOCUMENT),

    PPTX("pptx", "file.type.pptx", "PPT2007+", "application/vnd.openxmlformats-officedocument.presentationml.presentation", DOCUMENT),

    WPS("wps", "file.type.wps", "WPS", "application/kswps", DOCUMENT),

    WPS_ET("et", "file.type.wps_et", "ET", "application/kset", DOCUMENT),

    WPS_DPS("dps", "file.type.wps_dps", "DPS", "application/ksdps", DOCUMENT)
    ;

    /**
     * {@code FileType} 的属性编辑器。
     */
    public static PropertyEditor propertyEditor() {
        return new FileTypePropertyEditor();
    }

    final String value;
    final String code;
    final String defaultText;
    final FileType parent;
    final String mimeType;
    private final Set<FileType> children = new HashSet<>();

    FileType(String value, String code, String defaultText, String mimeType, FileType parent) {
        this.value = value;
        this.code = code;
        this.defaultText = defaultText;
        this.parent = parent;
        this.mimeType = mimeType;
        if (this.parent != null) {
            this.parent.children.add(this);
        }
    }

    FileType(String value, String code, String defaultText, String mimeType) {
        this(value, code, defaultText, mimeType, null);
    }

    @Override
    public String getText() {
        return I18n.getOrDefault(getCode(), getDefaultText());
    }

    @Contract(pure = true)
    @Override
    @JsonValue
    public String getValue() {
        return value;
    }

    @Contract(pure = true)
    public String getCode() {
        return code;
    }

    @Contract(pure = true)
    public String getDefaultText() {
        return defaultText;
    }

    @Contract(pure = true)
    public FileType getParent() {
        return parent;
    }

    public boolean isParented() {
        return getParent() == null && children.size() > 0;
    }

    @Contract(pure = true)
    @NotNull
    public String getMimeType() {
        return mimeType;
    }

    @NotNull
    @Override
    @SuppressWarnings("unchecked")
    public List<FileType> getChildren() {
        return ImmutableList.copyOf(children);
    }

    @Contract("_, !null -> !null")
    public static FileType of(String text, FileType def) {
        if (text == null || (text = text.trim()).isEmpty()) {
            return def;
        }
        // Fixed parse of when file extension is upper case.
        String t = text.toUpperCase(), v = text.toLowerCase();
        for (FileType type : values()) {
            if (v.equals(type.value) ||
                    t.equals(type.name())) {
                return type;
            }
        }
        return def;
    }

    @NotNull
    public static FileType of(String text) {
        return of(text, UNKNOWN);
    }

    /**
     * 返回所有允许上传至服务器的图片格式。
     */
    public static List<FileType> uploadImages() {
        return ImmutableList.of(JPEG, PNG, GIF, BMP, WBMP);
    }

    /**
     * 检查指定的图片文件类型是否允许被上传至服务器。
     *
     * @param type 要检查的类型。
     * @return 如果图片文件类型不允许被上传至服务器，则返回{@code true}，否则{@code false}
     */
    public static boolean isUpImageType(FileType type) {
        return type != null &&
                (type == JPEG || type == PNG || type == GIF || type == WBMP || type == BMP);
    }

    /**
     * 返回所有表示图片的{@code FileType} 的集合。
     */
    public static List<FileType> images() {
        return ImmutableList.copyOf(IMAGE.children);
    }

    /**
     * 返回所有表示音频的{@code FileType} 的集合。
     */
    public static List<FileType> audios() {
        return ImmutableList.copyOf(AUDIO.children);
    }

    /**
     * 返回所有表示视频的{@code FileType} 的集合。
     */
    public static List<FileType> videos() {
        return ImmutableList.copyOf(VIDEO.children);
    }

    /**
     * 返回所有表示压缩文件的{@code FileType} 的集合。
     */
    public static List<FileType> compressed() {
        return ImmutableList.copyOf(COMPRESSED.children);
    }

    /**
     * 返回所有表示文档的{@code FileType} 的集合。
     */
    public static List<FileType> documents() {
        return ImmutableList.copyOf(DOCUMENT.children);
    }

    private static class FileTypePropertyEditor extends PropertyEditorSupport {

        @Override
        public void setAsText(String text) throws IllegalArgumentException {
            if (text == null || (text = text.trim()).isEmpty()) {
                setValue(UNKNOWN);
            } else {
                setValue(of(text));
            }
        }
    }
}
